﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;

namespace Odyssey.Controls.Internals
{
    internal class VirtualIntervalCollection : IList, INotifyCollectionChanged, INotifyPropertyChanged, IDisposable
    {
        private IList source;
        private int thresholdCount = 0;

        public VirtualIntervalCollection(IList source, int threshold)
        {
            this.thresholdCount = threshold;
            this.source = source;
            INotifyCollectionChanged ns = source as INotifyCollectionChanged;
            if (ns != null) ns.CollectionChanged += new NotifyCollectionChangedEventHandler(OnCollectionChanged);
            INotifyPropertyChanged np = source as INotifyPropertyChanged;
            if (np != null) np.PropertyChanged += new PropertyChangedEventHandler(OnPropertyChanged);
        }

        public void Dispose()
        {
            GC.SuppressFinalize(this);
            INotifyCollectionChanged ns = source as INotifyCollectionChanged;
            if (ns != null) ns.CollectionChanged -= new NotifyCollectionChangedEventHandler(OnCollectionChanged);
            INotifyPropertyChanged np = source as INotifyPropertyChanged;
            if (np != null) np.PropertyChanged -= new PropertyChangedEventHandler(OnPropertyChanged);

        }

        ~VirtualIntervalCollection()
        {
            Dispose();
        }

        void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            var eh = PropertyChanged;
            if (eh != null) eh(this, e);
        }

        void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            var eh = CollectionChanged;
            if (eh != null) eh(this, e);
        }

        public int ThresholdCount
        {
            get { return thresholdCount; }
            set
            {
                if (value != thresholdCount)
                {
                    int c1 = Count;
                    thresholdCount = value;
                    int c2 = Count;
                    if (c1 != c2)
                    {
                        OnPropertyChanged("Count");
                        if (c2 > c1) SimulateItemAdded(c1, c2);
                    }
                }
            }
        }

        private void SimulateItemAdded(int from, int to)
        {
            int count = source.Count;
            from = Math.Min(from, count - 1);
            to = Math.Min(to, count );
            if (from < to)
            {
                var eh = CollectionChanged;
                if (eh != null)
                {
                    for (int i = from; i < to; i++)
                    {
                        object item = source[i];
                        eh(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, i));
                    }
                }
                //       OnPropertyChanged("Count");
            }
        }


        public int Add(object value)
        {
            return source.Add(value);
        }

        public void Clear()
        {
            //source.Clear();
        }

        public bool Contains(object value)
        {
            return source.Contains(value);
        }

        public int IndexOf(object value)
        {
            return source.IndexOf(value);
        }

        public void Insert(int index, object value)
        {
            //            source.Insert(index, value);
        }

        public bool IsFixedSize
        {
            get { return false; }
        }

        public bool IsReadOnly
        {
            get { return source.IsReadOnly; }
        }

        public void Remove(object value)
        {
            //            source.Remove(value);
        }

        public void RemoveAt(int index)
        {
            //         source.RemoveAt(index);
        }

        public object this[int index]
        {
            get
            {
                return source[index];
            }
            set
            {
                //            source[index] = value;
            }
        }

        public void CopyTo(Array array, int index)
        {
            source.CopyTo(array, index);
        }

        public int Count
        {
            get { return Math.Min(thresholdCount, source.Count); }
        }

        public bool IsSynchronized
        {
            get { return source.IsSynchronized; }
        }

        public object SyncRoot
        {
            get { return source.SyncRoot; }
        }

        public IEnumerator GetEnumerator()
        {
            return source.GetEnumerator();
        }

        protected void OnPropertyChanged(string propertyName)
        {
            var eh = PropertyChanged;
            if (eh != null) eh(this, new PropertyChangedEventArgs(propertyName));
        }


        public event NotifyCollectionChangedEventHandler CollectionChanged;

        public event PropertyChangedEventHandler PropertyChanged;
    }
}
